using System;
using System.Drawing;
using System.Windows.Forms;
using SpellCenter.Core;
using SpellCenter.UI.Properties;

namespace SpellCenter.UI
{
    internal partial class SpellGridControl : UserControl
    {
        private SpellGridViewControlPM _model;

        public event DataGridViewRowEventHandler RowChanged;
        private void OnRowChanged(DataGridViewRowEventArgs e)
        {
            DataGridViewRowEventHandler handler = RowChanged;
            if (handler != null)
                handler(this, e);
        }

        private void Grid_SelectionChanged(object sender, EventArgs e)
        {
            if (_grid.SelectedRows.Count == 1)
            {
                OnRowChanged(new DataGridViewRowEventArgs(_grid.SelectedRows[0]));
            }
            _grid.Focus();
            if(_grid.SelectedRows.Count > 0)
                _model.ViewWordContext(_grid.SelectedRows[0].Index );
        }

        public void MoveToNextRow()
        {
            _grid.Focus();
            SendKeys.Send("{DOWN}");
        }

        public SpellGridViewControlPM Model
        {
            get
            {
                if(_model == null)
                {
                    throw new InvalidOperationException("ContextControl must be set before Model can be used.");
                }
                return _model;
            }
        }

        private WordContextControl _contextControl;

        public WordContextControl ContextControl
        {
            get { return _contextControl; }
            set
            {
                _contextControl = value;
                _model = new SpellGridViewControlPM(_contextControl);
            }
        }

        private void PimpOutDataGrid()
        {
            _grid.ScrollBars = ScrollBars.Vertical;
            _grid.BackgroundColor = Color.Ivory;
            _grid.AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue;
            _grid.AlternatingRowsDefaultCellStyle.SelectionBackColor = Color.CornflowerBlue;
            _grid.AlternatingRowsDefaultCellStyle.SelectionForeColor = Color.Black;
            _grid.DefaultCellStyle.BackColor = Color.GhostWhite;
            _grid.DefaultCellStyle.SelectionBackColor = Color.CornflowerBlue;
            _grid.DefaultCellStyle.SelectionForeColor = Color.Black;

            _wordCol.Width = Settings.Default.SpellGrid_wordColumnWidth;
            _statusCol.Width = Settings.Default.SpellGrid_StatusColumnWidth;
            _occurrenceCol.Width = Settings.Default.SpellGrid_occurencesColumnWidth;
        }

        private void Grid_RowsAdded(object sender, EventArgs e)
        {
            SetFont(Settings.Default.GridFont);
            Focus();
        }

        private readonly bool _hasBeenInitialized = false;
        public SpellGridControl()
        {
            InitializeComponent();
            PimpOutDataGrid();
            _grid.Columns.Add("blankColumn", "");
            _grid.Columns["blankColumn"].ReadOnly = true;
            _grid.ScrollBars = ScrollBars.Vertical;
            Load += SpellGridControl_Resize;
            _grid.CellFormatting += Grid_CellFormating;
            _grid.RowsAdded += Grid_RowsAdded;
            _grid.SelectionChanged += Grid_SelectionChanged;
            _grid.ColumnWidthChanged += delegate { SpellGridControl_Resize(this, EventArgs.Empty); };
#if DEBUG
            _grid.DataError += Grid_DataError;
            _hasBeenInitialized = true;
        }

        private static void Grid_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            string message = string.Format("Data Error: {0}; Context: {1}", e.Context, e.Context);
            throw new Exception(message, e.Exception);
#endif
        }

        private void Grid_CellFormating(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if(e.ColumnIndex == _grid.Columns["_statusCol"].Index)
            {
                if(e.Value.GetType() == typeof(string))
                {
                    string status = (string) e.Value;
                    e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                    switch (status)
                    {
                        case SpellWordInfo.STATUS_UNKNOWN:
                            e.CellStyle.ForeColor = Color.Blue;
                            e.CellStyle.SelectionForeColor = Color.Blue;
                            break;
                        case SpellWordInfo.STATUS_GOOD:
                            e.CellStyle.ForeColor = Color.Green;
                            e.CellStyle.SelectionForeColor = Color.Green;
                            break;
                        case SpellWordInfo.STATUS_BAD:
                            e.CellStyle.ForeColor = Color.Red;
                            e.CellStyle.SelectionForeColor = Color.Red;
                            break;
                        default:
                            e.CellStyle.ForeColor = Color.Black;
                            e.CellStyle.SelectionForeColor = Color.White;
                            break;
                    }
                }
            }
        }

        public void InitializeCorpus(string filename, IIndexingManager indexer)
        {
            _model.OpenConfigFile(filename, indexer);
            _spellWordBindingSource.DataSource = _model.Data;
        }

        public void InitializeCorpus(FilesInCorpusList config, IIndexingManager indexer)
        {
            _model.OpenConfigFile(config, indexer);
            _spellWordBindingSource.DataSource = _model.Data;
        }

        private void SpellGridControl_Resize(object sender, EventArgs e)
        {
            int sum = 0;
            for (int i = 0; i < _grid.Columns.Count - 1; i++)
                sum += _grid.Columns[i].Width;
            _grid.Columns[_grid.Columns.Count - 1].Width = (Width - sum < 0 ? 0 : Width - sum);
            if(_hasBeenInitialized)
            {
                Settings.Default.SpellGrid_occurencesColumnWidth = _occurrenceCol.Width;
                Settings.Default.SpellGrid_StatusColumnWidth = _statusCol.Width;
                Settings.Default.SpellGrid_wordColumnWidth = _wordCol.Width;
                Settings.Default.Save();
            }
        }

        public void SetFont(Font font)
        {
            Font tmp = _grid.DefaultCellStyle.Font;
            if (tmp != _occurrenceCol.HeaderCell.Style.Font && _occurrenceCol.HeaderCell.Style.Font != null)
            {
                tmp = _occurrenceCol.HeaderCell.Style.Font;
            }
            _grid.Font = font;
            _wordCol.HeaderCell.Style.Font = tmp;
            _statusCol.HeaderCell.Style.Font = tmp;
            _occurrenceCol.HeaderCell.Style.Font = tmp;

            Settings.Default.GridFont = font;
            Settings.Default.Save();
            _grid.AutoResizeRows();
        }

        public void HandleIndexingFinished(object sender, EventArgs e)
        {
            Model.FillDataWithSpellWords();

            try
            {
                _grid.Invoke(new MethodInvoker(SetDataSource));
            }
            catch(ArgumentOutOfRangeException)
            {
                // Something went wrong, try to recover.
                // This condition happens in Windows.Forms code and I have no idea how/why it happens,
                //  but this seems to appease it
                if(!_grid.InvokeRequired)
                    SetDataSource();
            }
            catch(InvalidOperationException)
            {
                // I believe that this only occurs when the program is terminating prematurely
                Application.Exit();
            }
        }

        internal void SetDataSource()
        {
            _spellWordBindingSource.DataSource = Model.Data;
        }
    }
}
